﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LucyGrid
{
	public class DebugInfo {
#if DEBUG
		public class StackFrame
		{
			public DateTime Stamp;
			public string Frame;
			public double TransitionTime;
			public StackFrame(string frame, DateTime lastTime)
			{
				Stamp = DateTime.Now;
				Frame = frame;
				TransitionTime = (Stamp - lastTime).TotalMilliseconds;
			}
		}
		public List<StackFrame> Stack = new List<StackFrame>();
		public string StackTrace()
		{
			return string.Join("\r\n",
				Stack.Select(s => string.Format("{0} ({1}ms): {2}", s.Stamp.ToString("hh:mm:ss.fff"), s.TransitionTime, s.Frame))
				.ToArray());
		}
#endif // DEBUG
		/// <summary>
		/// DEBUG and RELEASE to avoid having to add #if DEBUG in the rest of the code
		/// </summary>
		/// <param name="frame"></param>
		public void Trace(string frame)
		{
#if DEBUG
			Stack.Add(new StackFrame(frame, Stack.Count != 0 ? Stack.Last().Stamp : DateTime.Now));
#endif
		}

		public override string ToString()
		{
#if DEBUG
			return StackTrace();
#else
			return base.ToString();
#endif
		}
	}
	/// <summary>
	/// Contains information about a piece of processing
	/// </summary>
	public class Chunk: DebugInfo
	{
		[Serializable]
		public class Header
		{
			/// <summary>
			/// Chunk identifier
			/// </summary>
			public int Id;
			/// <summary>
			/// Specifies if the execution returned an exception
			/// </summary>
			public bool IsError { get; set; }
		}
		/// <summary>
		/// Chunk metadata
		/// </summary>
		public Header Head;
		/// <summary>
		/// Data used as input/output for process
		/// </summary>
		public Object Data;

		public Chunk() { }
		public Chunk(Stream s, Type dataType) {
			var parts = GridUtils.Deserialize(s, typeof(Header), dataType);
			Head = (Header)parts.First();
			Data = parts.Skip(1).First();
			
		}

		public void Serialize(Stream s) {
			GridUtils.Serialize(s, Head, Data);
		}
			 
	}

	public class ChunkInfo
	{
		public ChunkInfo(int id, object data) {
			Chunk = new Chunk()
			{
				Head = new Chunk.Header()
				{
					Id = id
				},
				Data = data
			};
		}
		/// <summary>
		/// Wrapper
		/// </summary>
		public Chunk Chunk;
		/// <summary>
		/// Chunk Id
		/// </summary>
		public int Id {
			get {
				return Chunk.Head.Id;
			}
			set {
				Chunk.Head.Id = value;
			}
		}

		public Object Data {
			get {
				return Chunk.Data;
			}
			set {
				Chunk.Data = value;
			}
		}
		/// <summary>
		/// Identifier of the gridnode processing the chunk
		/// </summary>
		public NodeInfo Node;
		/// <summary>
		/// Indicates if the chunk has been locked for processing
		/// </summary>
		public bool ReqProcessing{
			get { return Node != null; }
		}

		/// <summary>
		/// Time when processing started
		/// </summary>
		public DateTime StartProcessing;

		/// <summary>
		/// The chunk has been returned
		/// </summary>
		public bool Notified;
		/// <summary>
		/// Exception
		/// </summary>
		public Exception ExceptionError
		{
			get { return Chunk.Head.IsError ? (Exception)Chunk.Data : null; }
		}
	}
}
